#define	_J_PROCESI_C_
#include "procesi.h"

#include "razno.h"
#include "liste.h"

//OPISNICI procesa
ZAUZMI ( j_proces_t, j_proces, NAJ_PROCESA );

//stvara novi proces s pocetnom dretvom - j-funckija
int j_stvori_proces ( void *param )
{
	struct {
		void ( *poc_funkc )( void * );	//pocetna funckija dreve
		void *param;			//parametar za funkciju
		void *stog;			//pocetni stog
		int prio;			//prioritet
		int rasp;			//koji rasporedjivac? FIFO, RR

		bool u_jezgri;			//nacin rada - privilegirani?
		void *pocetna_adresa;
		uint32 velicina;

	} *p = param;

	PARAMNULL ( p );

	int id = DOHVATI ( j_proces );

	if ( id == -1 ) {
		j_ispisi("Nema slobodnog opisnika procesa\n");
		return -1;
	}

	j_proces_t *proces = &j_proces[id];

	arh_zauzmi_spremnik ( &proces->spremnik, p->pocetna_adresa,
				p->velicina, p->u_jezgri );

	proces->id = id;
	proces->u_jezgri = p->u_jezgri;

	int id_dretve = j_stvori_dretvu_i ( p, id );

	if ( id_dretve == -1 ) {
		OBRISI ( j_proces, id );

		return -1;
	}
	else {
		proces->dretva = j_dohvati_opisnik ( id_dretve );
		proces->dretva->iduci_p = NULL; //prva dretva procesa

		return id;
	}
}

//doraditi/ispitati
int j_zavrsi_proces ( void *param )
{
	int *pid = param;
	int id, id_dretve;

	if (pid == NULL)
		id = j_aktivni_proces();
	else
		id = *pid;

	if ( id < 0 || id > NAJ_PROCESA || PROVJERI_SLOBODNO ( j_proces, id ) ){
		j_ispisi ( "Nepoznati proces\n" );
		return -1;
	}

	OBRISI ( j_proces, id );

	j_proces_t *proces = &j_proces[id];

	//obrisi dretve - popravi
	while ( proces->dretva != NULL ) {
		//zavrsi dretvu
		id_dretve = j_opdr_id ( proces->dretva );

		//makni je iz liste za proces
		proces->dretva = proces->dretva->iduci_p;
		proces->dretva->id_procesa = -1;

		j_zavrsi_dretvu ( &id_dretve );
	}

	//j_ispisi("Proces %d zavrsen\n", id);

	return 0;
}

//poziva se pri stvaranju nove dretve
void j_proces_postavi_dretvu ( int id_procesa, void *_opd, void *kontekst,
			       void *stog, void *pokreni_dretvu,
			       void *poc_funkc, void *param )
{
	j_dretva_t *opd = _opd;
	j_proces_t *proces = &j_proces[id_procesa];

	opd->iduci_p = proces->dretva;
	proces->dretva = opd;

	arh_pripremi_novu_dretvu ( &proces->spremnik, opd, kontekst, stog,
		pokreni_dretvu, poc_funkc, param );
}

//gotovu dretvu makni iz popisa procesa
void j_makni_dretvu_procesu ( int id_procesa, void *_opd )
{
	j_proces_t *proces = &j_proces[id_procesa];
	j_dretva_t *opd = _opd, *iter = proces->dretva;

	if ( iter == opd ) {
		proces->dretva = iter->iduci_p;
	}
	else {
		while ( iter->iduci_p ) {
			if ( iter->iduci_p == opd ) {
				iter->iduci_p = opd->iduci_p;
				break;
			}
			iter = iter->iduci_p;
		}
	}

	if ( proces->dretva == NULL && 
	     !PROVJERI_SLOBODNO ( j_proces, id_procesa ) )
		j_zavrsi_proces ( &id_procesa );
}

//dohvati opisnik spremnika za proces
void *j_oppr_spremnik ( int id )
{
	return &j_proces[id].spremnik;
}

//pretvara adresu jezgre u adresu za program
void *j_jup ( int id_procesa, void *adr_u_jezgri )
{
	return arh_jup ( &j_proces[id_procesa].spremnik, adr_u_jezgri );
}

//pretvara adresu programa u adresu koja je dohvatljiva iz jezgre
void *j_puj ( int id_procesa, void *adr_u_programu )
{
	return arh_puj ( &j_proces[id_procesa].spremnik, adr_u_programu );
}


//test procesa u jezgrinom prostoru (u absolutnim adresama)

//stog za takav proces
int proces_x_stog[VELICINA_STOGA / sizeof(int)];
void *pproces_x_stog = POCETAK_STOGA(proces_x_stog, VELICINA_STOGA/sizeof(int));

#include <pozivi_jezgre.h>
#include <ispis.h>
#include <vrijeme.h>
#include <programi.h>
void proces_x ( void *param )
{
	//moze koristiti samo funkcije jezgre:
	//	ili pozivati izravno ili preko prekida
	//"sucelje" je u relativnim adresama i ne moze se izravno koristiti,
	//ali ... (vidi primjere)

	//izravnim pozivom jezgrine funkcije:
	j_ispisi ( "[%s] Eto opakog procesa!\n", __FUNCTION__ );


	//pozivom jezgrine funkcije prekidom:
	struct test_ispisa { //parametri redom ...
		char *poruka;
		char *param1;
	} ti;
	ti.poruka = "[%s] Ispis preko poziva jezgrinih funkcija!\n";
	ti.param1 = (char *) __FUNCTION__;
	J_FUNKCIJA ( ISPISI, &ti );


	//"igranje s adresama"
	//oprez: u tim se funkcijama ne smiju koristiti globalne varijable
	extern char programi_pocetak;
	uint odmak = (uint) &programi_pocetak;

	(ispisi + odmak) ( "[%s] Preko 'sucelja'! :)\n", __FUNCTION__ );

	vrijeme_t koliko;
	koliko.sekunde = 1;
	koliko.nsekunde = 0;

	( odgodi + odmak ) (koliko);

	j_ispisi ( "[%s] Kraj opakog procesa!\n", __FUNCTION__ );

	//iduce ne funkcionira jer se pri ispisu koriste adrese konstanti koje
	//su u "relativnom obliku"
	// ( pocetna_dretva + odmak ) ( NULL );
}

